header{
package parser;
import collector.*;
import java.util.Hashtable;
import java.util.ArrayList;
import collector.StatementGroup;
import collector.Collector;
import collector.FileObj;
import collector.Statement;
import java.util.Vector;
import java.util.Enumeration;
}
/** Java 1.5 AST Recognizer Grammar
 *
 * Author: (see java.g preamble)
 *
 * This grammar is in the PUBLIC DOMAIN
 */
class JavaTreeParser extends TreeParser;

options {
	importVocab = Java;
}
{
//===Code duplication
int statID = 0;
FileObj file;
private Collector collector;

public JavaTreeParser(Collector collector, FileObj file){
	tokenNames = _tokenNames;
	this.file = file;
	this.collector = collector;
}

public int getMax(int a, int b){
	return (a>b)?a:b;
}
//remove null elements
public void refineArray(Vector<AST> v){
    for (Enumeration<AST> e = v.elements() ; e.hasMoreElements() ;) {
        AST t = e.nextElement();
        if (t == null) {
            v.removeElement(t);
        }
    }
}
public void reportError(RecognitionException ex) {
     Token token = null;
     if ( ex instanceof MismatchedTokenException ) {
         token = ((CodeReviewAST)((MismatchedTokenException)ex).node).token;
     }
     else if ( ex instanceof NoViableAltException ) {
         token = ((CodeReviewAST)((NoViableAltException)ex).node).token;
     }
     System.err.println("syntax error at "+token+" in tree: "+ex.toString());
}
}
compilationUnit
	:	(packageDefinition)?
		(importDefinition)*
		(typeDefinition)*
	;

packageDefinition
	:	#( PACKAGE_DEF annotations identifier )
	;

importDefinition
	:	#( IMPORT identifierStar )
	|	#( STATIC_IMPORT identifierStar )
	;

typeDefinition
	:	#(CLASS_DEF #(c:CLASS_H modifiers IDENT (typeParameters)? extendsClause implementsClause)
	    {
            TextLine tl = new TextLine();
            ((CodeReviewAST)c).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.CLASS_S, s);

            //System.out.println(tl.toString());
	    }
	    objBlock )
	|	#(INTERFACE_DEF #(i:INTERFACE_H modifiers IDENT (typeParameters)? extendsClause)
	    {
            TextLine tl = new TextLine();
            ((CodeReviewAST)i).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.INTF_S, s);

            //System.out.println(tl.toString());
	    }
	    interfaceBlock )
	|	#(ENUM_DEF modifiers IDENT implementsClause enumBlock )
	|	#(ANNOTATION_DEF modifiers IDENT annotationBlock )
	;

typeParameters
	:	#(TYPE_PARAMETERS (typeParameter)+)
	;

typeParameter
	:	#(TYPE_PARAMETER IDENT (typeUpperBounds)?)
	;

typeUpperBounds
	:	#(TYPE_UPPER_BOUNDS (classOrInterfaceType)+)
	;

typeSpec
	:	#(TYPE typeSpecArray)
	;

typeSpecArray
	:	#( ARRAY_DECLARATOR typeSpecArray )
	|	mytype:type {((CodeReviewAST)(mytype)).setAstType(TYPE);}
	;

type
	:	classOrInterfaceType
	|	builtInType
	;

classOrInterfaceType
	:	IDENT (typeArguments)?
	|	#( DOT classOrInterfaceType )
	;

typeArguments
	:	#(TYPE_ARGUMENTS (typeArgument)+)
	;

typeArgument
	:	#(	TYPE_ARGUMENT
			(	typeSpec
			|	wildcardType
			)
		)
	;

wildcardType
	:	#(WILDCARD_TYPE (typeArgumentBounds)?)
	;

typeArgumentBounds
	:	#(TYPE_UPPER_BOUNDS (classOrInterfaceType)+)
	|	#(TYPE_LOWER_BOUNDS (classOrInterfaceType)+)
	;

builtInType
	:	"void"
	|	"boolean"
	|	"byte"
	|	"char"
	|	"short"
	|	"int"
	|	"float"
	|	"long"
	|	"double"
	;

modifiers
	:	#( MODIFIERS (modifier)* )
	;

modifier
	:	"private"
	|	"public"
	|	"protected"
	|	"static"
	|	"transient"
	|	"final"
	|	"abstract"
	|	"native"
	|	"threadsafe"
	|	"synchronized"
	|	"const"
	|	"volatile"
	|	"strictfp"
	|	annotation
	;

annotations
	:	#(ANNOTATIONS (annotation)* )
	;

annotation
	:	#(ANNOTATION identifier (annotationMemberValueInitializer | (anntotationMemberValuePair)+)? )
	;

annotationMemberValueInitializer
	:	conditionalExpr | annotation | annotationMemberArrayInitializer
	;

anntotationMemberValuePair
	:	#(ANNOTATION_MEMBER_VALUE_PAIR IDENT annotationMemberValueInitializer)
	;

annotationMemberArrayInitializer
	:	#(ANNOTATION_ARRAY_INIT (annotationMemberArrayValueInitializer)* )
	;

annotationMemberArrayValueInitializer
	:	conditionalExpr | annotation
	;

extendsClause
	:	#(EXTENDS_CLAUSE (classOrInterfaceType)* )
	;

implementsClause
	:	#(IMPLEMENTS_CLAUSE (classOrInterfaceType)* )
	;


interfaceBlock
	:	#(	OBJBLOCK
			(	methodDecl
			|	va:variableDef
                {
                    TextLine tl = new TextLine();
                    ((CodeReviewAST)va).getInfo(tl);

                    Statement s = new Statement(file,tl);
                    collector.insertStatement(StatementGrouping.VAR_DEF_S, s);

                    //System.out.println(tl.toString());
                }
			|	typeDefinition
			)*
		)
	;

objBlock
	:	#(	OBJBLOCK
			(	ctorDef
			|	methodDef
			|	va:variableDef
                {
                    TextLine tl = new TextLine();
                    ((CodeReviewAST)va).getInfo(tl);

                    Statement s = new Statement(file,tl);
                    collector.insertStatement(StatementGrouping.VAR_DEF_S, s);
                    //System.out.println(tl.toString());
                }
			|	typeDefinition
			|	#(STATIC_INIT slist)
			|	#(INSTANCE_INIT slist)
			)*
		)
	;

annotationBlock
	:	#(	OBJBLOCK
			(	annotationFieldDecl
			|	variableDef
			|	typeDefinition
			)*
		)
	;

enumBlock
	:	#(	OBJBLOCK
			(
				enumConstantDef
			)*
			(	ctorDef
			|	methodDef
			|	variableDef
			|	typeDefinition
			|	#(STATIC_INIT slist)
			|	#(INSTANCE_INIT slist)
			)*
		)
	;

ctorDef
	:	#(CTOR_DEF #(ct:CTOR_H modifiers (typeParameters)? methodHead)
        {
            TextLine tl = new TextLine();
            ((CodeReviewAST)ct).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.CTOR_S, s);
            //System.out.println(tl.toString());
        }
	    (slist)?)
	;

methodDecl
	:	#(me:METHOD_DEF modifiers (typeParameters)? typeSpec methodHead)
	    {
	        TextLine tl = new TextLine();
            ((CodeReviewAST)me).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.MET_DEC_S, s);
            //System.out.println(tl.toString());
	    }
	;

methodDef
	:	#(METHOD_DEF #(me:METHOD_D modifiers (typeParameters)? typeSpec methodHead)
	    {
	        TextLine tl = new TextLine();
            ((CodeReviewAST)me).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.MET_DEF_S, s);
            //System.out.println(tl.toString());
	    }
	    (slist)?)
	;

variableDef
	:	#(VARIABLE_DEF modifiers typeSpec variableDeclarator varInitializer)
	;

parameterDef
	:	#(PARAMETER_DEF modifiers typeSpec IDENT )
	;

variableLengthParameterDef
	:	#(VARIABLE_PARAMETER_DEF modifiers typeSpec variableName )
	;

annotationFieldDecl
	:	#(ANNOTATION_FIELD_DEF modifiers typeSpec IDENT (annotationMemberValueInitializer)?)
	;

enumConstantDef
	:	#(ENUM_CONSTANT_DEF annotations IDENT (elist)? (enumConstantBlock)?)
	;

enumConstantBlock
	:	#(	OBJBLOCK
			(	methodDef
			|	variableDef
			|	typeDefinition
			|	#(INSTANCE_INIT slist)
			)*
		)
	;

objectinitializer
	:	#(INSTANCE_INIT slist)
	;

variableDeclarator
	:	variableName
	|	LBRACK variableDeclarator
	;

varInitializer
	:	#(ASSIGN initializer)
	|
	;

initializer
	:	expression
	|	arrayInitializer
	;

arrayInitializer
	:	#(ARRAY_INIT (initializer)*)
	;

methodHead
    :	#(METHOD_H IDENT #( PARAMETERS (parameterDef)* ) (throwsClause)?)
    ;


throwsClause
	:	#( "throws" (classOrInterfaceType)* )
	;

identifier
	:	IDENT
	|	#( DOT identifier IDENT )
	;

identifierStar
	:	IDENT
	|	#( DOT identifier (STAR|IDENT) )
	;

slist
	:	#( SLIST (stat)* )
	;

stat:	typeDefinition
	|	va:variableDef
	    {
	        TextLine tl = new TextLine();
            ((CodeReviewAST)va).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.VAR_DEF_S, s);
            //System.out.println(tl.toString());
	    }
	|	exp:expression
	    {
	        TextLine tl = new TextLine();
            ((CodeReviewAST)exp).getInfo(tl);
            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.EX_S, s);
            //System.out.println(tl.toString());
	    }
	|	#(la:LABELED_STAT i:IDENT
	    {
	        TextLine tl = new TextLine();
            ((CodeReviewAST)la).getNodeInfo(tl);
            ((CodeReviewAST)i).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.LABEL_S, s);
            //System.out.println(tl.toString());
	    }
	    stat)
	|	#(is:"if" e:expression
	    {
	        TextLine tl = new TextLine();
            ((CodeReviewAST)is).getNodeInfo(tl);
            ((CodeReviewAST)e).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.IF_S, s);
            //System.out.println(tl.toString());
	    }
	    stat (stat)? )

	|
	    #(fs:"for"
				{AST f=null;}
				(#(fh:FOR_H #(FOR_INIT ((variableDef)+ | elist)?)
				        #(FOR_CONDITION (expression)?)
				        #(FOR_ITERATOR (elist)?))
                    {f=fh;}
			    | #(fe:FOR_EACH_CLAUSE parameterDef expression)
			        {f=fe;}
				)
				    {
                        TextLine tl = new TextLine();
                        ((CodeReviewAST)fs).getNodeInfo(tl);
                        ((CodeReviewAST)f).getInfo(tl);

                        Statement s = new Statement(file,tl);
                        collector.insertStatement(StatementGrouping.FOR_S, s);
                        //System.out.println(tl.toString());
                    }
			stat
		)
	|	#(wh:"while" we:expression
	            {
                    TextLine tl = new TextLine();
                    ((CodeReviewAST)wh).getNodeInfo(tl);
                    ((CodeReviewAST)we).getInfo(tl);

                    Statement s = new Statement(file,tl);
                    collector.insertStatement(StatementGrouping.WHILE_S, s);
                    //System.out.println(tl.toString());
                }
	    stat)
	|	#("do" stat de:expression)
	            {
                    TextLine tl = new TextLine();
                    ((CodeReviewAST)de).getInfo(tl);

                    Statement s = new Statement(file,tl);
                    collector.insertStatement(StatementGrouping.DO_S, s);
                    //System.out.println(tl.toString());
                }
	|	#(b:"break" (IDENT)? )
	    {
            TextLine tl = new TextLine();
            ((CodeReviewAST)b).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.BR_S, s);
            //System.out.println(tl.toString());
        }
	|	#(c:"continue" (IDENT)? )
	    {
            TextLine tl = new TextLine();
            ((CodeReviewAST)c).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.CON_S, s);
            //System.out.println(tl.toString());
        }
	|	#(r:"return" (expression)? )
	    {
            TextLine tl = new TextLine();
            ((CodeReviewAST)r).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.RET_S, s);
            //System.out.println(tl.toString());
        }
	|	#(sw:"switch" se:expression
        {
            TextLine tl = new TextLine();
            ((CodeReviewAST)sw).getNodeInfo(tl);
            ((CodeReviewAST)se).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.SW_S, s);
            //System.out.println(tl.toString());
        }
        (caseGroup)*)
	|	#(t:"throw" expression)
	    {
            TextLine tl = new TextLine();
            ((CodeReviewAST)t).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.THR_S, s);
            //System.out.println(tl.toString());
        }
	|	#(sy:"synchronized" sep:expression
	    {
            TextLine tl = new TextLine();
            ((CodeReviewAST)sy).getNodeInfo(tl);
            ((CodeReviewAST)sep).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.SYN_S, s);
            //System.out.println(tl.toString());
        }
        stat)
	|	tryBlock
	|	slist // nested SLIST
	|	#(a:"assert" expression (expression)?)
        {
            TextLine tl = new TextLine();
            ((CodeReviewAST)a).getInfo(tl);

            Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.ASSR_S, s);
            //System.out.println(tl.toString());
        }
	|	EMPTY_STAT
	;

caseGroup
	:	#(CASE_GROUP
	    (#(c:"case" expression)
            {
                TextLine tl = new TextLine();
                ((CodeReviewAST)c).getInfo(tl);

                Statement s = new Statement(file,tl);
                collector.insertStatement(StatementGrouping.CASE_S, s);
                //System.out.println(tl.toString());
            }
        | "default"
        )+ slist)
	;

tryBlock
	:	#( "try" slist (handler)* (#("finally" slist))? )
	;

handler
	:	#( c:"catch" cp:parameterDef
	    {
            TextLine tl = new TextLine();
            ((CodeReviewAST)c).getNodeInfo(tl);
            ((CodeReviewAST)cp).getInfo(tl);

             Statement s = new Statement(file,tl);
            collector.insertStatement(StatementGrouping.CAT_S, s);
            //System.out.println(tl.toString());
        }
	    slist )
	;

elist
	:	#( ELIST (expression)* )
	;

expression
	:	#(EXPR expr)
	;

expr
	:	conditionalExpr
	|	#(ASSIGN expr expr)			// binary operators...
	|	#(PLUS_ASSIGN expr expr)
	|	#(MINUS_ASSIGN expr expr)
	|	#(STAR_ASSIGN expr expr)
	|	#(DIV_ASSIGN expr expr)
	|	#(MOD_ASSIGN expr expr)
	|	#(SR_ASSIGN expr expr)
	|	#(BSR_ASSIGN expr expr)
	|	#(SL_ASSIGN expr expr)
	|	#(BAND_ASSIGN expr expr)
	|	#(BXOR_ASSIGN expr expr)
	|	#(BOR_ASSIGN expr expr)
	;

conditionalExpr
	:	#(QUESTION expr expr expr)	// trinary operator
	|	#(LOR expr expr)
	|	#(LAND expr expr)
	|	#(BOR expr expr)
	|	#(BXOR expr expr)
	|	#(BAND expr expr)
	|	#(NOT_EQUAL expr expr)
	|	#(EQUAL expr expr)
	|	#(LT expr expr)
	|	#(GT expr expr)
	|	#(LE expr expr)
	|	#(GE expr expr)
	|	#(SL expr expr)
	|	#(SR expr expr)
	|	#(BSR expr expr)
	|	#(PLUS expr expr)
	|	#(MINUS expr expr)
	|	#(DIV expr expr)
	|	#(MOD expr expr)
	|	#(STAR expr expr)
	|	#(INC expr)
	|	#(DEC expr)
	|	#(POST_INC expr)
	|	#(POST_DEC expr)
	|	#(BNOT expr)
	|	#(LNOT expr)
	|	#("instanceof" expr expr)
	|	#(UNARY_MINUS expr)
	|	#(UNARY_PLUS expr)
	|	primaryExpression
	;

primaryExpression
	:	variableName
	|	#(	DOT
			(	expr
				(	variableName
				|	arrayIndex
				|	"this"
				|	"class"
				|	newExpression
				|	"super"
				|	(typeArguments)? // for generic methods calls
				)
			|	#(ARRAY_DECLARATOR typeSpecArray)
			|	builtInType ("class")?
			)
		)
	|	arrayIndex
	|	#(METHOD_CALL primaryExpression (typeArguments)? elist)
	|	ctorCall
	|	#(TYPECAST typeSpec expr)
	|	newExpression
	|	constant:constant {((CodeReviewAST)(constant)).setAstType(LITERAL);}
	|	"super"
	|	ct:"true" {((CodeReviewAST)(ct)).setAstType(LITERAL);}
	|	cf:"false" {((CodeReviewAST)(cf)).setAstType(LITERAL);}
	|	"this"
	|	cn:"null" {((CodeReviewAST)(cn)).setAstType(LITERAL);}
	|	typeSpec // type name used with instanceof
	;

ctorCall
	:	#( CTOR_CALL elist )
	|	#( SUPER_CTOR_CALL
			(	elist
			|	primaryExpression elist
			)
		 )
	;

arrayIndex
	:	#(INDEX_OP expr expression)
	;

constant
	:	NUM_INT
	|	CHAR_LITERAL
	|	STRING_LITERAL
	|	NUM_FLOAT
	|	NUM_DOUBLE
	|	NUM_LONG
	;

newExpression
	:	#(	"new" (typeArguments)? type
			(	newArrayDeclarator (arrayInitializer)?
			|	elist (objBlock)?
			)
		)

	;

newArrayDeclarator
	:	#( ARRAY_DECLARATOR (newArrayDeclarator)? (expression)? )
	;

variableName
	:	ident:IDENT {((CodeReviewAST)(ident)).setAstType(IDENT);}
	;